package com.haizhi.crm.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.haizhi.crm.biz.builder.MsgSearchQoBuilder;
import com.haizhi.crm.biz.constant.*;
import com.haizhi.crm.biz.dao.FavouriteDao;
import com.haizhi.crm.biz.dao.HistoryViewDao;
import com.haizhi.crm.biz.dao.VisitRecordDao;
import com.haizhi.crm.biz.model.*;
import com.haizhi.crm.biz.service.BrowseCountService;
import com.haizhi.crm.biz.service.CompanyService;
import com.haizhi.crm.biz.service.HistoryViewService;
import com.haizhi.crm.biz.service.VisitRecordService;
import com.haizhi.crm.biz.task.message.engine.MessageActualPush;
import com.haizhi.crm.biz.task.message.model.ContextDto;
import com.haizhi.crm.biz.util.MessageUtil;
import com.haizhi.crm.common.constant.BizStatus;
import com.haizhi.crm.common.constant.CrmConstant;
import com.haizhi.crm.common.constant.CrmSchema;
import com.haizhi.crm.common.constant.EntityType;
import com.haizhi.crm.common.exception.UnexpectedStatusException;
import com.haizhi.crm.common.jpa.Criteria;
import com.haizhi.crm.common.jpa.Restrictions;
import com.haizhi.crm.common.json.JSONUtils;
import com.haizhi.crm.common.log.GLog;
import com.haizhi.crm.common.log.LogFactory;
import com.haizhi.crm.common.model.PageResponse;
import com.haizhi.crm.common.model.Response;
import com.haizhi.crm.common.rest.RestService;
import com.haizhi.crm.common.util.CommonUtils;
import com.haizhi.crm.common.util.DateUtils;
import com.haizhi.crm.common.util.MD5Utils;
import com.haizhi.crm.search.builder.SearchQoBuilder;
import com.haizhi.crm.search.model.SearchQo;
import com.haizhi.crm.search.model.SearchResp;
import com.haizhi.crm.search.model.SearchVo;
import com.haizhi.crm.search.service.SearchService;
import com.haizhi.crm.sys.auth.dao.DepartmentDao;
import com.haizhi.crm.sys.auth.dao.UserDao;
import com.haizhi.crm.sys.auth.model.UserDo;
import com.haizhi.crm.sys.auth.model.UserResultVo;
import com.haizhi.crm.sys.auth.model.UserVo;
import com.haizhi.crm.sys.message.dao.MessageCategoryDao;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 拜访记录service
 * Created by yangyijun on 2018/6/5.
 */
@Service
public class VisitRecordServiceImpl implements VisitRecordService {

    private static final GLog LOG = LogFactory.getLogger(VisitRecordServiceImpl.class);
    private static final String addVisit = "拜访日程纪录";
    private static final String LOCAL_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @Autowired
    private BrowseCountService browseCountService;

    @Autowired
    private VisitRecordDao visitRecordDao;

    @Autowired
    private UserDao userDao;
    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    private SearchService searchService;

    @Autowired
    private CompanyService companyService;

    @Autowired
    private FavouriteDao favouriteDao;

    @Autowired
    private HistoryViewDao historyViewDao;

    @Autowired
    private RestService dcInboundAPIHttpSender;

    @Autowired
    private MessageCategoryDao messageCategoryDao;

    @Autowired
    private MessageActualPush messageActualPush;
    @Autowired
    private HistoryViewService historyViewService;

    @Value("${graph.userName:}" )
    private String graphUsername;

    @Value("${graph.password:}" )
    private String graphPwd;

    @Value("${graph.domain:}" )
    private String esDomain;

    @Value("${graph.createBatch.apiUri:}" )
    private String createBatchUri;

    @Value("${graph.inbound.apiUri:}" )
    private String inboundUri;

    @Transactional
    public Response save(VisitRecordQo visitRecordQo) {
        try {
            VisitRecordDo visitRecordDo = persist(visitRecordQo);
            importEs(visitRecordDo, CrmOperateType.CREATE);
            return Response.success();
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_SAVE_ERROR, e);
        }
    }

    public void pushMessage(VisitRecordDo visitRecordDo, Long visitRecordId) {
        ContextDto contextDto = new ContextDto();
        contextDto.setMsgType(addVisit);
        contextDto.setMsgSchema(MessageType.VISIT);
        contextDto.setEventType(addVisit);
        contextDto.setDetailKey(visitRecordDo.getObjectKey());
        contextDto.setDatabases(MysqlConstant.DATABASE);
        String userName = "";
        UserVo userVo = userDao.findBy(visitRecordDo.getCreatedById());
        if (userVo != null) {
            userName = userVo.getName();
        }
        if (null == visitRecordId) {
            contextDto.setTitle(userName + "创建了关联您的日程" );
        } else {
            contextDto.setTitle(userName + "修改了关联您的日程" );
        }
        contextDto.setMsgCategoryId(messageCategoryDao.findByName(addVisit).get(0).getId());

        List<MessageUserResourceDo> messageUserResourceDos = new ArrayList<>();
        MessageUserResourceDo messageUserResourceDo = new MessageUserResourceDo();
        messageUserResourceDo.setMessageSourceType(MessageSourceType.SHARE);
        messageUserResourceDos.add(messageUserResourceDo);

        MessageUserVo messageUserVo = new MessageUserVo();
        messageUserVo.setUserId(visitRecordDo.getUserId());
        messageUserVo.setStatus(MessageStatus.UNREAD);
        messageUserVo.setMessageUserResourceDoList(messageUserResourceDos);

        Map<Long, MessageUserVo> messageUserVoMap = new HashMap<>();
        String[] visitorIds = visitRecordDo.getVisitorIds().split("," );
        for (String visitorId : visitorIds) {
            messageUserVoMap.put(Long.parseLong(visitorId), messageUserVo);
        }

        contextDto.setMessageUserVoMap(messageUserVoMap);

        String customerKey = visitRecordDo.getCustomerKey();
        if (!StringUtils.isBlank(customerKey)) {
            SearchQo searchQo = MsgSearchQoBuilder.get(CrmSchema.CRM, customerKey);
            SearchVo searchVo = searchService.search(searchQo);
            List<Map<String, String>> datas = MessageUtil.toList(searchVo.getSearchResp().getData());
            Map<String, String> company = datas.get(0);
            MessageClientDo messageClientDo = new MessageClientDo();
            messageClientDo.setCompanyId(customerKey);
            messageClientDo.setCompanyName(company.get(MessageConstant.NAME));
            if (company.get(MessageConstant.IS_CUSTOMER).equals(MessageConstant.TRUE))
                messageClientDo.setInner(true);
            else
                messageClientDo.setInner(false);
            contextDto.getMessageClientDos().add(messageClientDo);
        }

        messageActualPush.push(contextDto);
    }

    @Transactional
    public Response update(VisitRecordQo visitRecordQo) {
        try {
            VisitRecordDo visitRecordDo = persist(visitRecordQo);
            importEs(visitRecordDo, CrmOperateType.UPDATE);
            return Response.success();
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_SAVE_ERROR, e);
        }
    }

    private Map<String, Object> getVisitRecordMap(VisitRecordDo visitRecordDo) {
        Map<String, Object> data = new HashMap<>();
        data.put("object_key", visitRecordDo.getObjectKey());
        data.put("address", visitRecordDo.getAddress());
        data.put("title", visitRecordDo.getTitle());
        data.put("customer_key", visitRecordDo.getCustomerKey());
        data.put("inner_event_key", visitRecordDo.getInnerEventKey());
        data.put("outer_event_key", visitRecordDo.getOuterEventKey());
        data.put("product_key", visitRecordDo.getProductKey());
        data.put("user_id", visitRecordDo.getUserId());
        data.put("visit_record_id", visitRecordDo.getVisitRecordId());
        data.put("record_desc", visitRecordDo.getRecordDesc());

        String visitTimeStart = DateUtils.utc2Local(DateUtils.toUTC(visitRecordDo.getVisitTimeStart()), DateUtils.ISO_8601_FORMAT, DateUtils.LOCAL_FORMAT);
        data.put("visit_time_start", visitTimeStart);

        String visitTimeEnd = DateUtils.utc2Local(DateUtils.toUTC(visitRecordDo.getVisitTimeEnd()), DateUtils.ISO_8601_FORMAT, DateUtils.LOCAL_FORMAT);
        data.put("visit_time_end", visitTimeEnd);

        data.put("visitor_ids", visitRecordDo.getVisitorIds());
        data.put("receiver", visitRecordDo.getReceiver());
        data.put("created_by", visitRecordDo.getCreatedById());

        String createdDt = DateUtils.utc2Local(DateUtils.toUTC(visitRecordDo.getCreatedDt()), DateUtils.ISO_8601_FORMAT, DateUtils.LOCAL_FORMAT);
        data.put("created_dt", createdDt);

        data.put("updated_by", visitRecordDo.getUpdateById());
        String updatedDt = DateUtils.utc2Local(DateUtils.toUTC(visitRecordDo.getUpdatedDt()), DateUtils.ISO_8601_FORMAT, DateUtils.LOCAL_FORMAT);
        data.put("updated_dt", updatedDt);
        return data;
    }

    private VisitRecordDo persist(VisitRecordQo visitRecordQo) throws Exception {
        VisitRecordDo visitRecordDo = new VisitRecordDo();
        Long userId = CommonUtils.getUserID();
        Long visitRecordId = visitRecordQo.getId();
        //mysql保存
        if (null == visitRecordId) {
            visitRecordDo.setCreatedById(userId);
            visitRecordDo.setCreatedDt(new Date());
            visitRecordDo.setEnabledFlag("1" );
            visitRecordDo.setObjectKey(MD5Utils.MD5(CrmSchema.VISIT_RECORD + System.currentTimeMillis()));
        } else {
            visitRecordDo = visitRecordDao.findOne(visitRecordQo.getId());
        }
        buildVisitRecord(visitRecordQo, visitRecordDo, userId);

        VisitRecordDo visitRecordDo1 = this.visitRecordDao.save(visitRecordDo);
        pushMessage(visitRecordDo1, visitRecordId);
        return visitRecordDo1;
    }

    private void buildVisitRecord(VisitRecordQo visitRecordQo, VisitRecordDo visitRecordDo, Long userId) {
        visitRecordDo.setRecordDesc(visitRecordQo.getRecordDesc());
        visitRecordDo.setReceiver(visitRecordQo.getReceiver());
        visitRecordDo.setProductKey(visitRecordQo.getProductKey());
        visitRecordDo.setInnerEventKey(visitRecordQo.getInnerEventKey());
        visitRecordDo.setOuterEventKey(visitRecordQo.getOuterEventKey());
        visitRecordDo.setAddress(visitRecordQo.getAddress());
        visitRecordDo.setCustomerKey(visitRecordQo.getCustomerKey());
        visitRecordDo.setTitle(visitRecordQo.getTitle());
        visitRecordDo.setVisitorIds(visitRecordQo.getVisitorIds());
        visitRecordDo.setVisitRecordId(visitRecordQo.getVisitRecordId());
        visitRecordDo.setVisitTimeStart(DateUtils.toLocal(visitRecordQo.getVisitTimeStart()));
        visitRecordDo.setVisitTimeEnd(DateUtils.toLocal(visitRecordQo.getVisitTimeEnd()));
        visitRecordDo.setUpdateById(userId);
        visitRecordDo.setUpdatedDt(new Date());
        visitRecordDo.setUserId(userId);
    }

    private void importEs(VisitRecordDo visitRecordDo, String crmOperateType) throws Exception {
        //获取数据接入批次号
        BatchNoReqQo batchNoReqQo = new BatchNoReqQo();
        batchNoReqQo.setGraphName(esDomain);
        batchNoReqQo.setSchemaName(CrmSchema.VISIT_RECORD);
        batchNoReqQo.setUserName(graphUsername);
        String batchNoStr = dcInboundAPIHttpSender.doPost(createBatchUri, batchNoReqQo, String.class);
        Long batchNo = Long.valueOf(batchNoStr);

        //ES、hbase保存
        DataInboundReqQo inboundReqDto = new DataInboundReqQo();
        inboundReqDto.setBatchNo(batchNo);
        inboundReqDto.setGraph(CrmSchema.CRM);
        inboundReqDto.setSchema(CrmSchema.VISIT_RECORD);
        inboundReqDto.setOperation_flag(crmOperateType);
        Map<String, Object> datas = getVisitRecordMap(visitRecordDo);
        if (CrmOperateType.CREATE.equals(crmOperateType)) {
            datas.put("browse_count", 0);
            datas.put("favorite_count", 0);
        }

        inboundReqDto.setDatas(new Object[]{datas});

        inboundReqDto.setUserInfo(new UserInfo(graphUsername, graphPwd, null));
        dcInboundAPIHttpSender.doPost(inboundUri, inboundReqDto, String.class);
    }

    @Override
    public Response findCreators() {
        try {
            Long curUserId = CommonUtils.getUserID();
            Long deptId = departmentDao.findByManagerId(curUserId);
            List<UserResultVo> userResultVos = userDao.findByUserIdAndDeptId(curUserId, deptId);
            return Response.success(userResultVos);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_GETCREATOR_ERROE, e);
        }
    }

    @Override
    public Response findCustomers(String queryType) {
        try {
            Long curUserId = CommonUtils.getUserID();
            List<String> customerKeys = getCustomerKeys(queryType, curUserId);
            if (CollectionUtils.isEmpty(customerKeys)) {
                return Response.success();
            }

            SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
            searchQoBuilder.setGraph(CrmSchema.CRM);
            searchQoBuilder.addSchemas(CrmSchema.COMPANY);
            searchQoBuilder.addTermFilter("object_key", customerKeys.toArray());
            SearchVo searchVo = searchService.search(searchQoBuilder.get());
            SearchResp searchResp = searchVo.getSearchResp();
            if (null == searchResp || null == searchResp.getData()) {
                return Response.success();
            }

            List<Map<String, Object>> companys = JSONUtils.jsonToListMap(JSON.toJSONString(searchResp.getData()));
            List<CompanyVo> companyVos = new ArrayList<>();
            for (Map<String, Object> map : companys) {
                CompanyVo companyVo = new CompanyVo();
                companyVo.setName(map.get("name" ).toString());
                companyVo.setObjectKey(map.get("object_key" ).toString());
                companyVos.add(companyVo);
            }
            return Response.success(companyVos);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.CUSTOMER_QUERY_ERROR, e);
        }
    }

    private List<String> getCustomerKeys(String queryType, Long curUserId) {
        List<String> customerKeys = null;
        if (CrmConstant.QUERYTYPE_UNDERLING.equals(queryType)) {
            Long deptId = departmentDao.findByManagerId(curUserId);
            List<Long> userIds = new ArrayList<>();
            List<Integer> userIdsTmp = userDao.findByDeptId(deptId);
            for (Integer id : userIdsTmp) {
                userIds.add(id.longValue());
            }
            userIds.remove(curUserId);
            if (userIds.size() == 0) {
                return null;
            }
            customerKeys = visitRecordDao.findCustomerKeysByUserIds(userIds.toArray(new Long[userIds.size()]));
        } else {
            customerKeys = visitRecordDao.findCustomerKeysByUserIds(new Long[]{curUserId});
        }
        return customerKeys;
    }

    @Override
    public Response search(VisitRecordSearchQo visitRecord) {
        try {
            Long curUserId = CommonUtils.getUserID();
            String queryType = visitRecord.getQueryType();
            List<Long> userIds = new ArrayList<>();
            if (CrmConstant.QUERYTYPE_MY.equals(queryType)) {//查询我的
                userIds.add(curUserId);
            } else if (CrmConstant.QUERYTYPE_UNDERLING.equals(queryType)) { //查询下属的
                Long deptId = departmentDao.findByManagerId(curUserId);
                if (null == deptId) {
                    return Response.success();
                }
                List<Integer> userIdsTmp = userDao.findByDeptId(deptId);
                for (Integer id : userIdsTmp) {
                    userIds.add(id.longValue());
                }
                userIds.remove(curUserId);
            } else {
                return Response.error(BizStatus.VISIT_RECORD_APIPARAM_ERROE);
            }
            Integer pageNo = visitRecord.getPageNo();
            Integer pageSize = visitRecord.getPageSize();

            Criteria<VisitRecordDo> c = buildCriteria(userIds, visitRecord);
            PageRequest pageAndSort = new PageRequest(pageNo - 1, pageSize, new Sort(new Sort.Order(Sort.Direction.DESC, "visitTimeStart" )));//分页和排序参数
            Page<VisitRecordDo> visitRecordList_page = visitRecordDao.findAll(c, pageAndSort);

            List<VisitRecordResultVo> visitRecordResultList = new ArrayList<>();
            List<VisitRecordDo> visitRecordList = visitRecordList_page.getContent();
            Long pageTotal = visitRecordList_page.getTotalElements();
            for (VisitRecordDo vr : visitRecordList) {
                VisitRecordResultVo vrResutl = new VisitRecordResultVo();
                try {
                    PropertyUtils.copyProperties(vrResutl, vr);
                } catch (Exception e) {
                    LOG.error(e);
                }
                this.setDetailInfo(vrResutl);
                visitRecordResultList.add(vrResutl);
            }
            return PageResponse.success()
                    .setPageInfo(pageTotal.intValue(), pageNo, pageSize)
                    .setData(visitRecordResultList);
        } catch (UnexpectedStatusException e) {
            LOG.error(BizStatus.VISIT_RECORD_QUERY_ERROR.getDesc(), e);
            return Response.error(BizStatus.VISIT_RECORD_QUERY_ERROR);
        }
    }

    private Criteria<VisitRecordDo> buildCriteria(List<Long> userIds, VisitRecordSearchQo visitRecord) {
        Criteria<VisitRecordDo> c = new Criteria<>();
        String endTime = visitRecord.getEndTime();
        String startTime = visitRecord.getStartTime();
        c.add(Restrictions.in("userId", userIds, true));
        if (StringUtils.isNotBlank(endTime) && StringUtils.isNotBlank(startTime)) {
            c.add(Restrictions.lte("visitTimeEnd", DateUtils.toLocal(endTime), true));
            c.add(Restrictions.gte("visitTimeStart", DateUtils.toLocal(startTime), true));
        }
        c.add(Restrictions.eq("customerKey", visitRecord.getCompanyKey(), true));
        c.add(Restrictions.eq("userId", visitRecord.getCreator(), true));
        c.add(Restrictions.like("title", visitRecord.getTitle(), true));
        return c;
    }

    /**
     * 根据ID查询拜访记录
     *
     * @param objectKey
     * @return
     */
    public Response findById(String objectKey) {
        try {
            VisitRecordResultVo result = getVisitRecordResultVo(objectKey);
            browseCountService.count(CrmSchema.VISIT_RECORD, objectKey);
            int browseCount = browseCountService.queryBrowseCount(CrmSchema.VISIT_RECORD, objectKey);
            result.setBrowseCount(browseCount);
            historyViewService.save(CrmSchema.VISIT_RECORD, objectKey, result.getTitle());
            return Response.success(result);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }

    private VisitRecordResultVo getVisitRecordResultVo(String objectKey) {
        VisitRecordResultVo result = new VisitRecordResultVo();
        VisitRecordDo vr = this.visitRecordDao.findByObjectKey(objectKey);
        if (vr == null) {
            return null;
        }
        try {
            PropertyUtils.copyProperties(result, vr);
        } catch (Exception e) {
            LOG.error(e);
        }

        //设置相关属性
        this.setDetailInfo(result);
        return result;
    }

    //设置相关属性：协同人员，客户信息
    public void setDetailInfo(VisitRecordResultVo visitRecordResult) {
        if (visitRecordResult == null) {
            return;
        }

        //协同人员
        String visitorIds = visitRecordResult.getVisitorIds();
        if (StringUtils.isNotBlank(visitorIds)) {
            String[] visitorIdsArray = visitorIds.split("," );
            Long[] ids = (Long[]) ConvertUtils.convert(visitorIdsArray, Long.class);
            List<UserResultVo> visitors = this.userDao.queryUsersByIds(ids);
            visitRecordResult.setVisitors(visitors);
        }

        //客户信息
        String customerKey = visitRecordResult.getCustomerKey();
        if (StringUtils.isNotBlank(customerKey)) {
            CompanyVo company = this.companyService.queryByCustomerKey(customerKey);
            visitRecordResult.setCustomer(company);
        }

        //客户经理信息
        Long userId = visitRecordResult.getUserId();
        if (null != userId) {
            UserDo user = this.userDao.findOne(userId);
            if (null != user) {
                visitRecordResult.setCreaterName(user.getName());
            }
        }

        //查询拜访记录是否被当前用户收藏
        Long curUserId = CommonUtils.getUserID();
        int count = this.favouriteDao.findFavouriteCount(curUserId, EntityType.VISIT_RECORD.getValue(), visitRecordResult.getObjectKey());
        visitRecordResult.setFavourited(count >= 1 ? true : false);
    }

    @Override
    public Response findAssociatedInnerEvents(String objectKey) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findByObjectKey(objectKey);
            return Response.success(getResponse(CrmSchema.EVENT_INNER, visitRecord.getInnerEventKey()));
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_ABOUTENTITY_ERROR, e);
        }
    }

    @Override
    public Response findAssociatedProducts(String objectKey) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findByObjectKey(objectKey);
            return Response.success(getResponse(CrmSchema.PRODUCT, visitRecord.getProductKey()));
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_ABOUTENTITY_ERROR, e);
        }
    }

    @Override
    public Response findAssociatedOuterEvents(String objectKey) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findByObjectKey(objectKey);
            return Response.success(getResponse(CrmSchema.EVENT_OUTTER, visitRecord.getOuterEventKey()));
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }

    @Override
    public Response findAssociatedCustomers(String objectKey) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findByObjectKey(objectKey);
            return Response.success(getResponse(CrmSchema.COMPANY, visitRecord.getCustomerKey()));
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }


    private List<Map<String, Object>> getResponse(String schemas, String key) {
        if (StringUtils.isBlank(key)) {
            return new ArrayList<>();
        }
        SearchQoBuilder searchQo = new SearchQoBuilder();
        searchQo.setGraph(CrmSchema.CRM);
        searchQo.addSchemas(schemas);
        searchQo.addTermFilter("object_key", key);
        SearchVo searchVo = this.searchService.search(searchQo.get());
        return JSONUtils.jsonToListMap(JSON.toJSONString(searchVo.getSearchResp().getData()));
    }


    /**
     * 查询拜访记录相关联的拜访记录
     *
     * @param objectKey
     * @return
     */
    public Response findAssociatedVisitRecords(String objectKey) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findByObjectKey(objectKey);
            Long id = visitRecord.getVisitRecordId();
            VisitRecordDo visit = visitRecordDao.findOne(id);
            List<VisitRecordResultVo> visitRecordResultVos = new ArrayList<VisitRecordResultVo>();
            if (null == visit) {
                return Response.success(visitRecordResultVos);
            }
            VisitRecordResultVo result = getVisitRecordResultVo(visit.getObjectKey());
            visitRecordResultVos.add(result);
            return Response.success(visitRecordResultVos);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }

    @Override
    public Response findAssociatedVisitRecords(String objectKey, String eventSchema) {
        try {
            List<VisitRecordResultVo> visitRecordResultVos = null;
            if (CrmSchema.EVENT_INNER.equals(eventSchema)) {
                visitRecordResultVos = visitRecordDao.findByInnerEventKey(objectKey);
            } else if (CrmSchema.EVENT_OUTTER.equals(eventSchema)) {
                visitRecordResultVos = visitRecordDao.findByOuterEventKey(objectKey);
            } else {
                visitRecordResultVos = visitRecordDao.findByProdutKey(objectKey);
            }
            List<VisitRecordVo> visitVos = getVisitRecordVos(visitRecordResultVos, null, null);
            return Response.success(visitVos);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }

    private List<VisitRecordVo> getVisitRecordVos(List<VisitRecordResultVo> visitRecordResultVos, String customerKey, String customerName) {
        List<VisitRecordVo> visitVos = new ArrayList<>();
        for (VisitRecordResultVo visit : visitRecordResultVos) {
            VisitRecordVo visitRecordVo = new VisitRecordVo();
            visitRecordVo.setCreator(visit.getCreaterName());
            if (null == customerKey) {
                visitRecordVo.setCustomerKey(visit.getCustomerKey());
                visitRecordVo.setCustomerName(getCustomerName(visit.getCustomerKey()));
            } else {
                visitRecordVo.setCustomerKey(customerKey);
                visitRecordVo.setCustomerName(customerName);
            }
            visitRecordVo.setObjectKey(visit.getObjectKey());
            visitRecordVo.setId(visit.getId());
            visitRecordVo.setStartTime(visit.getVisitTimeStart());
            visitRecordVo.setTitle(visit.getTitle());

            //查询拜访记录是否被当前用户收藏
            Long curUserId = CommonUtils.getUserID();
            int count = this.favouriteDao.findFavouriteCount(curUserId, CrmSchema.VISIT_RECORD, visit.getObjectKey());
            visitRecordVo.setFavourited(count >= 1 ? true : false);

            visitVos.add(visitRecordVo);
        }
        return visitVos;
    }

    @Transactional(readOnly = false)
    public Response delete(Long visitRecordId) {
        try {
            //删除拜访记录
            visitRecordDao.delete(visitRecordId);
            //删除收藏信息
            favouriteDao.deleteByEntityTypeAndEntityID(EntityType.VISIT_RECORD.getValue(), String.valueOf(visitRecordId));
            return Response.success();
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_DELETE_ERROR, e);
        }
    }

    /**
     * 查询拜访记录所关联企业的其他拜访记录
     *
     * @param visitRecordId
     * @return
     */
    public Response othersVisitRecordOfCompany(Long visitRecordId) {
        try {
            VisitRecordDo visitRecord = this.visitRecordDao.findOne(visitRecordId);
            String customerKey = visitRecord.getCustomerKey();
            List<VisitRecordResultVo> result = this.visitRecordDao.queryByCustomerKey(customerKey);
            List<VisitRecordResultVo> deleteVos = new ArrayList<>();

            for (VisitRecordResultVo vrr : result) {
                if (vrr.getId() == visitRecordId) {
                    deleteVos.add(vrr);
                } else {
                    this.setDetailInfo(vrr);
                }
            }
            result.removeAll(deleteVos);
            return Response.success(result);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_ABOUTENTITY_ERROR, e);
        }
    }

    /**
     * 查询当前用户最近浏览的拜访记录
     *
     * @return
     */
    public Response recentViewVisitRecord(int count) {
        try {
            List<VisitRecordResultVo> result = this.historyViewDao.recentViewVisitRecord(CommonUtils.getUserID());
            if (result.size() > count) {
                result = result.subList(0, count);
            }
            return Response.success(result);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_RECENTVIEW_ERROR, e);
        }
    }


    public Response findByTitle(String title) {
        try {
            return Response.success(this.visitRecordDao.queryByTitle(title));
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_RECENTVIEW_ERROR, e);
        }

    }

    @Override
    public Response findByCustomerKey(CustomerVisitRecordQo customerVisitRecordQo) {
        try {
            String customerKey = customerVisitRecordQo.getCustomerKey();
            String customerName = getCustomerName(customerKey);
            Integer pageNo = customerVisitRecordQo.getPageNo();
            Integer pageSize = customerVisitRecordQo.getPageSize();
            Page visitPage = visitRecordDao.findByCustomerKey(customerKey, new PageRequest(pageNo - 1, pageSize, Sort.Direction.DESC, "visitTimeStart" ));
            List<VisitRecordResultVo> visitRecordResultVos = visitPage.getContent();

            List<VisitRecordVo> visitVos = getVisitRecordVos(visitRecordResultVos, customerKey, customerName);
            long total = visitPage.getTotalElements();
            return new PageResponse(visitVos, total, pageNo, pageSize);
        } catch (Exception e) {
            throw new UnexpectedStatusException(BizStatus.VISIT_RECORD_QUERY_ERROR, e);
        }
    }

    private String getCustomerName(String customerKey) {
        SearchQoBuilder searchQoBuilder = new SearchQoBuilder();
        searchQoBuilder.setGraph(CrmSchema.CRM);
        searchQoBuilder.addSchemas(CrmSchema.COMPANY);
        searchQoBuilder.addTermFilter("object_key", customerKey);

        Object data = searchService.search(searchQoBuilder.get()).getSearchResp().getData();
        List<Map<String, Object>> customers = JSONUtils.jsonToListMap(JSON.toJSONString(data));
        Map<String, Object> customerMap = customers.get(0);
        return customerMap.get("name" ).toString();
    }
}
